#include "alsaty.h"
#include "dcuinformation.h"
#include <QDateTime>

extern unsigned char djbj_type;

#define myCout()                                                   \
    qDebug() << "[" << __FILE__ << __FUNCTION__ << __LINE__ << "]" \
             << ":"

int set_hwparams(snd_pcm_t *handle, snd_pcm_hw_params_t *params, unsigned int channels, unsigned int rate, snd_pcm_uframes_t &buffer_size,
                 snd_pcm_uframes_t &period_size)
{
    unsigned int      rrate;
    snd_pcm_uframes_t size;
    int               err, dir;
    /* choose all parameters */
    err = snd_pcm_hw_params_any(handle, params);
    if (err < 0)
    {
        qDebug() << "Broken configuration for playback: no configurations available: " << snd_strerror(err);
        return err;
    }
    /* set hardware resampling */
    err = snd_pcm_hw_params_set_rate_resample(handle, params, 1);
    if (err < 0)
    {
        qDebug() << "Resampling setup failed for playback: " << snd_strerror(err);
        return err;
    }
    /* set the interleaved read/write format */
    err = snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
    if (err < 0)
    {
        qDebug() << "Access type not available for playback: " << snd_strerror(err);
        return err;
    }
    /* set the sample format */
    err = snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE);
    if (err < 0)
    {
        qDebug() << "Sample format not available for playback: " << snd_strerror(err);
        return err;
    }
    /* set the count of channels */
    err = snd_pcm_hw_params_set_channels(handle, params, channels);
    if (err < 0)
    {
        qDebug() << QString("Channels count (%1) not available for playbacks: %2").arg(channels).arg(snd_strerror(err));
        return err;
    }
    /* set the stream rate */
    rrate = rate;
    err   = snd_pcm_hw_params_set_rate_near(handle, params, &rrate, 0);
    if (err < 0)
    {
        qDebug() << QString("Rate %1Hz not available for playback: %2").arg(rate).arg(snd_strerror(err));
        return err;
    }
    if (rrate != rate)
    {
        qDebug() << QString("Rate doesn't match (requested %1Hz, get %2Hz)\n").arg(rate).arg(err);
        return -EINVAL;
    }
    /* set the buffer time */
    unsigned int buffer_time = 512000; /* ring buffer length in us */
    err                      = snd_pcm_hw_params_set_buffer_time_near(handle, params, &buffer_time, &dir);
    if (err < 0)
    {
        qDebug() << QString("Unable to set buffer time %1 for playback: %2").arg(buffer_time).arg(snd_strerror(err));
        return err;
    }
    err = snd_pcm_hw_params_get_buffer_size(params, &size);
    if (err < 0)
    {
        qDebug() << QString("Unable to get buffer size for playback: %1").arg(snd_strerror(err));
        return err;
    }
    buffer_size = size;
    qDebug() << "buffer_size = " << int(buffer_size);
    /* set the period time */
    unsigned int period_time = 512000; /* period time in us */

    err = snd_pcm_hw_params_set_period_time_near(handle, params, &period_time, &dir);
    if (err < 0)
    {
        qDebug() << QString("Unable to set period time %1 for playback: %2").arg(period_time).arg(snd_strerror(err));
        return err;
    }
    err = snd_pcm_hw_params_get_period_size(params, &size, &dir);
    if (err < 0)
    {
        qDebug() << "Unable to get period size for playback: " << snd_strerror(err);
        return err;
    }
    period_size = size;
    qDebug() << "period_size = " << int(period_size);
    /* write the parameters to device */
    err = snd_pcm_hw_params(handle, params);
    if (err < 0)
    {
        qDebug() << "Unable to set hw params for playback: " << snd_strerror(err);
        return err;
    }

    return 0;
}

int set_swparams(snd_pcm_t *handle, snd_pcm_sw_params_t *swparams, snd_pcm_uframes_t &buffer_size, snd_pcm_uframes_t &period_size)
{
    int err;
    /* get the current swparams */
    err = snd_pcm_sw_params_current(handle, swparams);
    if (err < 0)
    {
        qDebug() << "Unable to determine current swparams for playback: " << snd_strerror(err);
        return err;
    }
    /* start the transfer when the buffer is almost full: */
    /* (buffer_size / avail_min) * avail_min */
    //    err = snd_pcm_sw_params_set_start_threshold(handle, swparams, (buffer_size / period_size) * period_size);
    err = snd_pcm_sw_params_set_start_threshold(handle, swparams, (buffer_size / period_size) * period_size / 4);
    if (err < 0)
    {
        qDebug() << "Unable to set start threshold mode for playback: " << snd_strerror(err);
        return err;
    }
    /* allow the transfer when at least period_size samples can be processed */
    /* or disable this mechanism when period event is enabled (aka interrupt like style processing) */
    err = snd_pcm_sw_params_set_avail_min(handle, swparams, period_size);
    if (err < 0)
    {
        qDebug() << "Unable to set avail min for playback: " << snd_strerror(err);
        return err;
    }

    /* write the parameters to the playback device */
    err = snd_pcm_sw_params(handle, swparams);
    if (err < 0)
    {
        qDebug() << "Unable to set sw params for playback: " << snd_strerror(err);
        return err;
    }

    return 0;
}

/*
 *   Underrun and suspend recovery
 */
int xrun_recovery(snd_pcm_t *handle, int err)
{
    qDebug() << "stream recovery" << err;
    if (err == -EPIPE)
    { /* under-run */
        err = snd_pcm_prepare(handle);
        if (err < 0) qDebug() << "Can't recovery from underrun, prepare failed: " << snd_strerror(err);
        return 0;
    }
    else if (err == -ESTRPIPE)
    {
        while ((err = snd_pcm_resume(handle)) == -EAGAIN) sleep(1); /* wait until the suspend flag is released */
        if (err < 0)
        {
            err = snd_pcm_prepare(handle);
            if (err < 0) qDebug() << "Can't recovery from suspend, prepare failed: " << snd_strerror(err);
        }
        return 0;
    }
    return err;
}

void ReadAudioThread::run()
{
    const unsigned int channels   = 1;
    const unsigned int rate       = 16000;
    const int          packetsize = 1024;

    snd_pcm_uframes_t buffer_size;
    snd_pcm_uframes_t period_size;

    int err = 0;

    snd_pcm_t *          handle;
    snd_pcm_hw_params_t *hwparams;
    snd_pcm_sw_params_t *swparams;

    snd_pcm_hw_params_alloca(&hwparams);
    snd_pcm_sw_params_alloca(&swparams);

    if ((err = snd_pcm_open(&handle, "default", SND_PCM_STREAM_CAPTURE, 0)) < 0)
    {
        qDebug() << "Playback open error: " << snd_strerror(err);
        exit(EXIT_FAILURE);
    }

    if ((err = set_hwparams(handle, hwparams, channels, rate, buffer_size, period_size)) < 0)
    {
        qDebug() << "Setting of hwparams failed: " << snd_strerror(err);
        exit(EXIT_FAILURE);
    }
    qDebug() << "Read buffer_size = " << buffer_size;
    qDebug() << "Read period_size = " << period_size;
    if ((err = set_swparams(handle, swparams, buffer_size, period_size)) < 0)
    {
        qDebug() << "Setting of swparams failed: " << snd_strerror(err);
        exit(EXIT_FAILURE);
    }
    qDebug() << "Read period_size = " << period_size;

    char       data[1024] = {0};
    QByteArray Data;
    QByteArray head;
    head.resize(300);
    head.fill(0x01);
    head[0] = 0;  //默认IP = 0无对应设备

    QUdpSocket TxAudioSocket;
    TxAudioSocket.setSocketOption(QAbstractSocket::MulticastLoopbackOption, 0);

    while (1)
    {
        m_lock.lock();
        if (!m_stop) break;
        m_lock.unlock();
        msleep(2);
        err = snd_pcm_readi(handle, data, packetsize / (2 * channels));

        if (err != packetsize / (2 * channels))
        {
            qDebug() << "Read error: " << snd_strerror(err);
            snd_pcm_recover(handle, err, 0);
        }
        else
        {
            Data.append(head);
            Data.append(data, packetsize);

            if (Data.size() >= packetsize + head.size())
            {
                if (djbj_type == RENGONG)  //人工广播
                {
                    TxAudioSocket.writeDatagram(Data.data(), packetsize + head.size(), QHostAddress("230.10.10.20"), 20020);
                }

                Data.remove(0, packetsize + head.size());
            }
        }
    }
    snd_pcm_drain(handle);
    snd_pcm_close(handle);
    snd_pcm_hw_free(handle);

    qDebug() << "音频发送线程结束";
}

// void WriteAudioThread::run()
//{
//    const unsigned int channels   = 1;
//    const unsigned int rate       = 16000;
//    const int          packetsize = 1024;

//    snd_pcm_uframes_t buffer_size;
//    snd_pcm_uframes_t period_size;

//    int err = 0;

//    snd_pcm_t *          handle;
//    snd_pcm_hw_params_t *hwparams;
//    snd_pcm_sw_params_t *swparams;

//    snd_pcm_hw_params_alloca(&hwparams);
//    snd_pcm_sw_params_alloca(&swparams);

//    if ((err = snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, 0)) < 0)
//    {
//        qDebug() << "Playback open error: " << snd_strerror(err);
//        exit(EXIT_FAILURE);
//    }

//    if ((err = set_hwparams(handle, hwparams, channels, rate, buffer_size, period_size)) < 0)
//    {
//        qDebug() << "Setting of hwparams failed: " << snd_strerror(err);
//        exit(EXIT_FAILURE);
//    }
//    qDebug() << "Write buffer_size = " << buffer_size;
//    qDebug() << "Write period_size = " << period_size;
//    if ((err = set_swparams(handle, swparams, buffer_size, period_size)) < 0)
//    {
//        qDebug() << "Setting of swparams failed: " << snd_strerror(err);
//        exit(EXIT_FAILURE);
//    }
//    qDebug() << "Write period_size = " << period_size;

//    const QHostAddress TC1AudioAddress = QHostAddress("230.10.10.20");
//    const QHostAddress TC2AudioAddress = QHostAddress("230.10.10.20");
//    const int          TCAudioPort     = 20020;

//    QUdpSocket RxAudioSocket;

//    if (StationInfo.DCUID_Flag == 0)  //司机对讲接听端接收数据地址保持不变
//    {
//        if (StationInfo.DCUID == 1)
//        //"DCU当前地址：车头"));
//        {
//            RxAudioSocket.bind(TC1AudioAddress, TCAudioPort, QUdpSocket::ShareAddress);
//            RxAudioSocket.joinMulticastGroup(TC1AudioAddress);
//        }
//        else if (StationInfo.DCUID == 6)  //"DCU当前地址：车尾"));
//        {
//            RxAudioSocket.bind(TC2AudioAddress, TCAudioPort, QUdpSocket::ShareAddress);
//            RxAudioSocket.joinMulticastGroup(TC2AudioAddress);
//        }
//    }
//    if (StationInfo.DCUID_Flag == 1)  //司机对讲发起端接收数据地址与原来倒置
//    {
//        if (StationInfo.DCUID == 1)
//        //"DCU当前地址：车头"));
//        {
//            RxAudioSocket.bind(TC2AudioAddress, TCAudioPort, QUdpSocket::ShareAddress);
//            RxAudioSocket.joinMulticastGroup(TC2AudioAddress);
//        }
//        else if (StationInfo.DCUID == 6)  //"DCU当前地址：车尾"));
//        {
//            RxAudioSocket.bind(TC1AudioAddress, TCAudioPort, QUdpSocket::ShareAddress);
//            RxAudioSocket.joinMulticastGroup(TC1AudioAddress);
//        }
//    }

//    snd_pcm_nonblock(handle, SND_PCM_NONBLOCK);
//    QByteArray Data;

//    bool dataok = false;
//    int  count  = 0;
//    while (1)
//    {
//        m_lock.lock();
//        if (!m_stop) break;
//        m_lock.unlock();

//        if (RxAudioSocket.hasPendingDatagrams())
//        {
//            char data[packetsize] = {0};
//            int  size             = RxAudioSocket.pendingDatagramSize();
//            RxAudioSocket.readDatagram(data, size);
//            Data.append(data, size);
//        }
//        else
//        {
//            msleep(1);
//        }

//        if (!dataok)
//        {
//            if (Data.size() > 4096)
//            {
//                dataok                = true;
//                char data[packetsize] = {0};
//                memcpy(data, Data.data(), packetsize);
//                Data.remove(0, packetsize);
//                myCout() << "DATA SIZE=" << Data.size();
//                err = snd_pcm_writei(handle, data, packetsize / (2 * channels));

//                memcpy(data, Data.data(), packetsize);
//                Data.remove(0, packetsize);
//                myCout() << "DATA SIZE=" << Data.size();
//                err = snd_pcm_writei(handle, data, packetsize / (2 * channels));

//                memcpy(data, Data.data(), packetsize);
//                Data.remove(0, packetsize);
//                myCout() << "DATA SIZE=" << Data.size();
//                err = snd_pcm_writei(handle, data, packetsize / (2 * channels));

//                memcpy(data, Data.data(), packetsize);
//                Data.remove(0, packetsize);
//                myCout() << "DATA SIZE=" << Data.size();
//                err = snd_pcm_writei(handle, data, packetsize / (2 * channels));
//                if (err < 0)
//                {
//                    if (xrun_recovery(handle, err) < 0)
//                    {
//                        qDebug() << "Write error: " << snd_strerror(err);
//                    }
//                }
//                alsaErrLog(QString("声卡恢复次数：%1").arg(count++));
//            }
//        }
//        if ((Data.size() > 2048) && dataok)
//        {
//            char data[packetsize] = {0};
//            memcpy(data, Data.data(), packetsize);
//            Data.remove(0, packetsize);

//            err = snd_pcm_writei(handle, data, packetsize / (2 * channels));

//            if (err < 0)
//            {
//                dataok = false;
//                myCout() << "DATA SIZE=" << Data.size() << "err=" << err;
//                alsaErrLog(QString("Data.size()=%1 err=%2").arg(Data.size()).arg(err));
//                if (xrun_recovery(handle, err) < 0)
//                {
//                    qDebug() << "Write error: " << snd_strerror(err);
//                }
//            }
//        }
//    }
//    snd_pcm_drain(handle);
//    snd_pcm_close(handle);
//    snd_pcm_hw_free(handle);

//    qDebug() << "音频接收线程结束";
//}

// void WriteAudioThread::WorkThread()
//{
//    m_lock.tryLock(10);
//    m_stop = true;
//    m_lock.unlock();
//}
////线程退出的接口函数，用户使用
// void WriteAudioThread ::stop()
//{
//    m_lock.tryLock(10);
//    m_stop = false;
//    m_lock.unlock();
//    qDebug() << "音频接收线程ID: " << QThread::currentThreadId();
//}

void ReadAudioThread::stop()
{
    m_lock.tryLock(100);
    m_stop = false;
    m_lock.unlock();
    qDebug() << "音频发送线程ID : " << QThread::currentThreadId();
}

void ReadAudioThread::WorkThread()
{
    m_lock.tryLock(100);
    m_stop = true;
    m_lock.unlock();
}
